﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;

namespace ImageProcessing
{
	public enum ImageType {HSI,YIQ,RGB};
	public partial class EnhancementDialog : Form
	{
		Bitmap bmIn;
		Bitmap bmOut;
		Bitmap bmModTh;
		Bitmap bmBaseTh;
		ImageType imageType = ImageType.RGB;
		const int THUMBNAILSIZE = 260;
		bool imageReady;
		bool isChanged = false;
		double[, ,] adImage;
		double[, ,] adImageTh;
		double[, ,] adImageModTh;
		double[, ,] adImageYIQHSI;
		double[, ,] adImageYIQHSITh;
		double[] adData;
		Timer tmr;

		delegate double[, ,] delEnhance(double[, ,] adImage, int nWidth, int nHeight, int nLower, int nUpper, out double[] adData, double[] adArgs);
		Dictionary<string, delEnhance> dictOperations;
		delEnhance delEnhanceOp;

		#region Constructors

		public EnhancementDialog()
			: this(null)
		{ }

		public EnhancementDialog(Bitmap bmin)
		{
			InitializeComponent();

			if (bmin != null)
			{
				imageReady = true;
				ImageIn = bmin;
			}//end if
			else
				imageReady = false;
			tmr = new Timer();
			tmr.Tick += new EventHandler(tmr_Tick);
			tmr.Interval = 500;
			tabMenu.SelectedTab = tabThreshold;
			dictOperations = new Dictionary<string, delEnhance>();
			fillComboBox();
			//fillMorphFilterComboBox();


		}

		void tmr_Tick(object sender, EventArgs e)
		{
			btnDoEnhance_Click(sender, e);
			tmr.Stop();
		}

		private void fillComboBox()
		{
			delEnhanceOp = Enhance.Linear;
			dictOperations.Add("Linear", delEnhanceOp);
			delEnhanceOp = Enhance.Bias;
			dictOperations.Add("Bias", delEnhanceOp);
			delEnhanceOp = Enhance.Gain;
			dictOperations.Add("Gain", delEnhanceOp);
			delEnhanceOp = Enhance.Exp;
			dictOperations.Add("Exp", delEnhanceOp);
			delEnhanceOp = Enhance.Root;
			dictOperations.Add("Root", delEnhanceOp);
			delEnhanceOp = Enhance.Contour;
			dictOperations.Add("Contour", delEnhanceOp);
			dictOperations.Add("Invert", null);
			dictOperations.Add("BinarySlice", null);

			KeyValuePair<string, delEnhance>[] kvpFunctions = dictOperations.ToArray();

			cmbboxEnhance.DataSource = kvpFunctions;
			cmbboxEnhance.DisplayMember = "Key";
		}
		#endregion Constructors

		#region Properties

		public Bitmap ImageIn
		{
			get { return bmIn; }
			set
			{
				bmIn = new Bitmap(value);
				//size thumbnail picboxes to proper size
				picBoxBase.Size = new Size(THUMBNAILSIZE, THUMBNAILSIZE);
				picBoxModified.Size = new Size(THUMBNAILSIZE, THUMBNAILSIZE);
				bmBaseTh = (Bitmap)value.GetThumbnailImage(THUMBNAILSIZE, THUMBNAILSIZE, null, IntPtr.Zero);
				bmModTh = new Bitmap(bmBaseTh);

				//normalize image for modifications
				this.Cursor = Cursors.WaitCursor;
				adImage = BitmapConversions.NormalizeRGB(bmIn);
				adImageTh = BitmapConversions.NormalizeRGB(bmBaseTh);
				this.Cursor = Cursors.Default;
				imageReady = true;
			}
		}

		#region OnPaint
		private void picBoxModified_Paint(object sender, PaintEventArgs e)
		{
			if (imageReady)
				picBoxModified.BackgroundImage = bmModTh;
		}

		private void picBoxBase_Paint(object sender, PaintEventArgs e)
		{
			if (imageReady)
				picBoxBase.BackgroundImage = bmBaseTh;
		}
		#endregion OnPaint

		public Bitmap ImageOut
		{
			get { return bmOut; }
			set { bmOut = new Bitmap(value); }
		}
		#endregion Properties





		private void trkbarUpper_ValueChanged(object sender, EventArgs e)
		{
			lblUpperVal.Text = trkbarUpper.Value.ToString();
			if (tmr.Enabled)
				tmr.Stop();
			tmr.Start();
		}

		private void trkbarLower_ValueChanged(object sender, EventArgs e)
		{
			lblLowerVal.Text = trkbarLower.Value.ToString();
			if (tmr.Enabled)
				tmr.Stop();
			tmr.Start();

		}

		private void btnDoEnhance_Click(object sender, EventArgs e)
		{
			doEffect(false, false);
			picboxThreshold.Invalidate();
			picBoxModified.Invalidate();
		}

		private void btnOk_Click(object sender, EventArgs e)
		{
			doEffect(true, false);
		}

		private void btnCommit_Click(object sender, EventArgs e)
		{
			doEffect(true, false);
			doEffect(false, true);
			picBoxBase.Invalidate();
		}

		private void doEffect(bool isBigImage, bool isBaseTh)
		{
			double[] adArgs = new double[4];
			string txtOperation = cmbboxEnhance.Text;
			double[,,] adImageTemp;
			double[, ,] adImageTemp2;
			
			try
			{
				adArgs[0] = Convert.ToDouble(txtboxP1.Text);
				adArgs[1] = Convert.ToDouble(txtboxP2.Text);
				adArgs[2] = Convert.ToDouble(txtboxP3.Text);
				adArgs[3] = Convert.ToDouble(txtboxP4.Text);
			} //end try
			catch
			{
				MessageBox.Show("Invalid Arguments. Please enter any floating point or integer value.");
				return;
			} //end catch

			byte bMask = (byte)Math.Pow(2.0, adArgs[0]);

			if (isBigImage)
			{
				if (cmbboxEnhance.Text == "Invert")
					bmOut = Enhance.Invert(new Bitmap(bmIn));
				else if (cmbboxEnhance.Text == "BinarySlice")
				{
					Enhance.getBitSlice(bmIn, ref bmOut, bMask);
				}
				else
				{
					if (radioRGB.Checked)
					{
						adImage = dictOperations[txtOperation](adImage, bmIn.Width, bmIn.Height, trkbarLower.Value, trkbarUpper.Value, out adData, adArgs);
						ImageOut = BitmapConversions.UnNormalizeRGB(adImage, bmIn.Width, bmIn.Height, true, bmModTh.PixelFormat);
					} //end if
					else
					{
						this.Cursor = Cursors.WaitCursor;
						if (radioYIQ.Checked)
						{
							adImageYIQHSI = BitmapConversions.YIQConversion(adImage, bmIn.Width, bmIn.Height, true);
							adImageTemp = dictOperations[txtOperation](adImageYIQHSI, bmIn.Width, bmIn.Height, trkbarLower.Value, trkbarUpper.Value, out adData, adArgs);
							adImageTemp2 = BitmapConversions.YIQConversion(adImageTemp, bmIn.Width, bmIn.Height, false);
							ImageOut = BitmapConversions.UnNormalizeRGB(adImageTemp2, bmIn.Width, bmIn.Height, true, bmIn.PixelFormat);
						}//end if
						else //HSI
						{
							adImageYIQHSI = BitmapConversions.HSIConversion(adImage, bmIn.Width, bmIn.Height, true,chkboxPitas.Checked);
							adImageTemp = dictOperations[txtOperation](adImageYIQHSI, bmIn.Width, bmIn.Height, trkbarLower.Value, trkbarUpper.Value, out adData, adArgs);
							adImageTemp2 = BitmapConversions.HSIConversion(adImageTemp, bmIn.Width, bmIn.Height, false, chkboxPitas.Checked);
							ImageOut = BitmapConversions.UnNormalizeRGB(adImageTemp2, bmIn.Width, bmIn.Height, true, bmIn.PixelFormat);
						}//end else
						this.Cursor = Cursors.Default;
					}//end else
					
				} //end else
			} //end if
			else
			{
				if (isBaseTh)
				//
				//Commit button Pressed
				{
					if (cmbboxEnhance.Text == "Invert")
						bmBaseTh = Enhance.Invert(bmBaseTh);
					else if (cmbboxEnhance.Text == "BinarySlice")
					{
						Enhance.getBitSlice(bmBaseTh, ref bmModTh, bMask);
						bmBaseTh = new Bitmap(bmModTh);
					}
					else
					{
						if (radioRGB.Checked)
						{
							adImageTh = dictOperations[txtOperation](adImageTh, THUMBNAILSIZE, THUMBNAILSIZE, trkbarLower.Value, trkbarUpper.Value, out adData, adArgs);
							bmBaseTh = BitmapConversions.UnNormalizeRGB(adImageTh, THUMBNAILSIZE, THUMBNAILSIZE, true, bmModTh.PixelFormat);
						} //end if
						else
						{
							this.Cursor = Cursors.WaitCursor;
							if (radioYIQ.Checked)
							{
								//adImageYIQHSITh = BitmapConversions.YIQConversion(adImageTh, THUMBNAILSIZE, THUMBNAILSIZE, true);
								adImageTemp = dictOperations[txtOperation](adImageYIQHSITh, THUMBNAILSIZE, THUMBNAILSIZE, trkbarLower.Value, trkbarUpper.Value, out adData, adArgs);
								adImageTemp2 = BitmapConversions.YIQConversion(adImageTemp, THUMBNAILSIZE, THUMBNAILSIZE, false);
								bmBaseTh = BitmapConversions.UnNormalizeRGB(adImageTemp2, THUMBNAILSIZE, THUMBNAILSIZE, true, bmModTh.PixelFormat);
							}//end if
							else //HSI
							{
								//adImageYIQHSITh = BitmapConversions.HSIConversion(adImageTh, THUMBNAILSIZE, THUMBNAILSIZE, true, chkboxPitas.Checked);
								adImageTemp = dictOperations[txtOperation](adImageYIQHSITh, THUMBNAILSIZE, THUMBNAILSIZE, trkbarLower.Value, trkbarUpper.Value, out adData, adArgs);
								adImageTemp2 = BitmapConversions.HSIConversion(adImageTemp, THUMBNAILSIZE, THUMBNAILSIZE, false, chkboxPitas.Checked);
								bmBaseTh = BitmapConversions.UnNormalizeRGB(adImageTemp2, THUMBNAILSIZE, THUMBNAILSIZE, true, bmModTh.PixelFormat);
							}//end else
							this.Cursor = Cursors.Default;
						}//end else
					}
				} //end if
				else
				{
					//Normal operation fired (The preview).
					//
					if (cmbboxEnhance.Text == "Invert")
						bmModTh = Enhance.Invert(new Bitmap(bmBaseTh));
					else if (cmbboxEnhance.Text == "BinarySlice")
					{
						Enhance.getBitSlice(bmBaseTh, ref bmModTh, bMask);
					}
					else
					{
						if (radioRGB.Checked)
						{
							adImageModTh = dictOperations[txtOperation](adImageTh, THUMBNAILSIZE, THUMBNAILSIZE, trkbarLower.Value, trkbarUpper.Value, out adData, adArgs);
							bmModTh = BitmapConversions.UnNormalizeRGB(adImageModTh, THUMBNAILSIZE, THUMBNAILSIZE, true, bmModTh.PixelFormat);
						} //end if
						else
						{
							this.Cursor = Cursors.WaitCursor;
							if (radioYIQ.Checked)
							{
								//adImageYIQHSITh = BitmapConversions.YIQConversion(adImageTh, THUMBNAILSIZE, THUMBNAILSIZE, true);
								adImageTemp = dictOperations[txtOperation](adImageYIQHSITh, THUMBNAILSIZE, THUMBNAILSIZE, trkbarLower.Value, trkbarUpper.Value, out adData, adArgs);
								adImageTemp2 = BitmapConversions.YIQConversion(adImageTemp, THUMBNAILSIZE, THUMBNAILSIZE, false);
								bmModTh = BitmapConversions.UnNormalizeRGB(adImageTemp2, THUMBNAILSIZE, THUMBNAILSIZE, true, bmModTh.PixelFormat);
							}//end if
							else //HSI
							{
								//adImageYIQHSITh = BitmapConversions.HSIConversion(adImageTh, THUMBNAILSIZE, THUMBNAILSIZE, true, chkboxPitas.Checked);
								adImageTemp = dictOperations[txtOperation](adImageYIQHSITh, THUMBNAILSIZE, THUMBNAILSIZE, trkbarLower.Value, trkbarUpper.Value, out adData, adArgs);
								adImageTemp2 = BitmapConversions.HSIConversion(adImageTemp, THUMBNAILSIZE, THUMBNAILSIZE, false, chkboxPitas.Checked);
								bmModTh = BitmapConversions.UnNormalizeRGB(adImageTemp2, THUMBNAILSIZE, THUMBNAILSIZE, true, bmModTh.PixelFormat);
							}//end else
							this.Cursor = Cursors.Default;
						}//end else
					}
				} //end else

			} //end else


		}

		private void picboxThreshold_Paint(object sender, PaintEventArgs e)
		{
			int nY, nYOff;
			nY = picboxThreshold.Height - 1;
			Point[] apPoints = new Point[256];

			if (adData != null)
			{
				for (int i = 0; i < 256; i++)
				{
					nYOff = (int)(adData[i] * 255.0);
					apPoints[i].X = i;
					apPoints[i].Y = nY - nYOff;

				} //end for

				e.Graphics.DrawLines(Pens.Blue, apPoints);
			} //end if
		}

		private void cmbboxEnhance_SelectedIndexChanged(object sender, EventArgs e)
		{
			btnDoEnhance_Click(sender, e);
		}

		private void radioRGB_Click(object sender, EventArgs e)
		{
			if (radioRGB.Checked)
			{
				adImageTh = BitmapConversions.NormalizeRGB(bmBaseTh);
				txtboxP2.Text = "1";
				imageType = ImageType.RGB;
			} //end if
			else if (radioYIQ.Checked)
			{
				adImageTh = BitmapConversions.NormalizeRGB(bmBaseTh);
				adImageYIQHSITh = BitmapConversions.YIQConversion(adImageTh, THUMBNAILSIZE, THUMBNAILSIZE, true);
				txtboxP2.Text = "2";
				imageType = ImageType.YIQ;
			} //end if
			else
			{
				adImageTh = BitmapConversions.NormalizeRGB(bmBaseTh);
				adImageYIQHSITh = BitmapConversions.HSIConversion(adImageTh, THUMBNAILSIZE, THUMBNAILSIZE, true, chkboxPitas.Checked);
				txtboxP2.Text = "3";
				imageType = ImageType.HSI;
			}
		}

		private void chkboxPitas_CheckedChanged(object sender, EventArgs e)
		{
			if (imageType == ImageType.HSI)
			{
				adImageTh = BitmapConversions.NormalizeRGB(bmBaseTh);
				adImageYIQHSITh = BitmapConversions.HSIConversion(adImageTh, THUMBNAILSIZE, THUMBNAILSIZE, true, chkboxPitas.Checked);
			}
		}




	}
}
